package com.sailing.xjpb.ipaas.client.core;

import com.sailing.xjpb.common.SailingAssert;
import com.sailing.xjpb.common.sercurity.SailingUserContext;
import com.sailing.xjpb.common.sercurity.SailingUserCurrentInfo;
import com.sailing.xjpb.ipaas.client.config.IpaasClientProperties;
import com.sailing.xjpb.ipaas.client.entity.bo.SipRoleBO;
import com.sailing.xjpb.ipaas.client.entity.bo.SipUserInfoBO;
import com.sailing.xjpb.ipaas.client.entity.dto.SipOrganizationDTO;
import com.sailing.xjpb.ipaas.client.entity.dto.SipRoleDTO;
import com.sailing.xjpb.ipaas.client.entity.dto.SipUserCurrentInfoDTO;
import com.sailing.xjpb.ipaas.client.entity.dto.SipUserOrgDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户上下文信息，用户获取当前用户信息和用户相关的信息
 *
 * @author YW
 */
@Slf4j
public final class UserContext implements ApplicationContextAware, SailingUserContext {

    /**
     * 存放访问IP
     */
    private static final ThreadLocal<String> IP_ADDRESS = new ThreadLocal<>();
    /**
     * 存放访问token
     */
    private static final ThreadLocal<String> AUTHORIZATION = new ThreadLocal<>();
    /**
     * 存放ipaas session
     */
    private static final ThreadLocal<String> IPAAS_SESSION_ID = new ThreadLocal<>();
    /**
     * 存放ipaas 租户信息
     */
    private static final ThreadLocal<String> IPAAS_TENANT_CODE = new ThreadLocal<>();
    /**
     * 存放当前用户信息
     */
    private static final ThreadLocal<SipUserCurrentInfoDTO> CURRENT_USER_INFO = new ThreadLocal<>();
    /**
     * 存放用户角色
     */
    private static final ThreadLocal<List<SipRoleDTO>> CURRENT_USER_ROLES_INFO = new ThreadLocal<>();

    private static ApplicationContext applicationContext;

    private static IpaasClientProperties ipaasClientProperties;

    /**
     * 获取当前登录用户信息
     *
     * @return 当前用户信息
     */
    public static SipUserCurrentInfoDTO currentUser() {
        SipUserCurrentInfoDTO currentUserInfo = CURRENT_USER_INFO.get();
        if (currentUserInfo == null) {
            currentUserInfo = remoteCurrentUser();
            CURRENT_USER_INFO.set(currentUserInfo);
        }
        return currentUserInfo;
    }

    /**
     * 判断当前用户是否具有角色中的一个角色
     *
     * @param roles 角色列表
     * @return true:至少拥有一个角色|fales：一个角色都没有
     */
    public static boolean hasOneOfRoles(String... roles) {
        List<String> userRoles = getUserRoles();
        userRoles.retainAll(Arrays.asList(roles));
        return !userRoles.isEmpty();
    }

    /**
     * 判断当前用户是否具有角色中的一个角色
     *
     * @param roles 角色列表
     * @return true:至少拥有一个角色|fales：一个角色都没有
     */
    public static boolean hasOneOfRoles(SipRoleBO... roles) {
        List<String> userRoles = getUserRoles();
        List<String> compareRoles = Arrays.stream(roles).map(SipRoleBO::getRoleEnName).collect(Collectors.toList());
        userRoles.retainAll(compareRoles);
        return !userRoles.isEmpty();
    }

    /**
     * 获取当前用户角色列表
     *
     * @return 用户角色名称
     */
    public static List<String> getUserRoles() {
        List<SipRoleDTO> currentUserRolesInfo = CURRENT_USER_ROLES_INFO.get();
        if (currentUserRolesInfo == null) {
            IpaasClientService currentUserContextService = getIpaasClientService();
            String currentUserName = currentUserName();
            String authorization = getBearerToken();
            currentUserRolesInfo = currentUserContextService.listRoles(authorization, currentUserName);
            if (currentUserRolesInfo == null) {
                currentUserRolesInfo = new ArrayList<>();
            }
            CURRENT_USER_ROLES_INFO.set(currentUserRolesInfo);
        }
        return currentUserRolesInfo.stream().map(SipRoleDTO::getRoleEnName).collect(Collectors.toList());
    }

    /**
     * 获取当前登录用户的用户登录名
     *
     * @return 用户登录名
     */
    public static String currentUserName() {
        SipUserCurrentInfoDTO currentUser = currentUser();
        return currentUser.getUsername();
    }

    /**
     * 获取当前登录用户的用户中文名
     *
     * @return 用户中文名
     */
    public static String currentUserCName() {
        SipUserCurrentInfoDTO currentUser = currentUser();
        return currentUser.getUsercname();
    }

    /**
     * 获取当前登录用户的用户ID
     *
     * @return 用户ID
     */
    public static String currentUserId() {
        SipUserCurrentInfoDTO currentUser = currentUser();
        return currentUser.getUserid();
    }

    /**
     * 获取当前登录用户的组织机构号码
     *
     * @return 组织机构编码
     */
    public static String currentOrgCode() {
        SipUserCurrentInfoDTO currentUser = currentUser();
        return currentUser.getOrgCode();
    }

    /**
     * 获取当前登录用户的组织机构ID
     *
     * @return 组织机构ID
     */
    public static String currentOrgId() {
        SipUserCurrentInfoDTO currentUser = currentUser();
        return currentUser.getOrgId();
    }

    /**
     * 为token添加bearer以符合bearer token格式
     * <p>
     * "abcdefg" ---> "bearer abcdefg"
     * <p>
     * "bearer abcdefg" ---> "bearer abcdefg"
     *
     * @return bearer token
     */
    public static String getBearerToken() {
        String token = AUTHORIZATION.get();
        if (token != null) {
            String bearerTokenName = ipaasClientProperties.getBearerTokenName();
            if (StringUtils.isNotBlank(bearerTokenName) && !token.startsWith(bearerTokenName)) {
                String[] tokenSplit = token.split(" ");
                if (tokenSplit.length == 2) {
                    token = tokenSplit[1];
                }
                token = ipaasClientProperties.getBearerTokenName() + " " + token;
            }
        }
        return token;
    }

    /**
     * 获取用户token
     *
     * @return 用户token
     */
    public static String getAuthorization() {
        return AUTHORIZATION.get();
    }

    /**
     * 绑定当前用户token
     *
     * @param authorization 用户票据信息
     */
    public static void setAuthorization(String authorization) {
        if (authorization != null) {
            AUTHORIZATION.set(authorization);
        }
    }

    /**
     * 设置ipaas session信息
     *
     * @param ipaasSessionId ipaasSessionId
     */
    public static void setIpaasSessionId(String ipaasSessionId) {
        if (ipaasSessionId != null) {
            IPAAS_SESSION_ID.set(ipaasSessionId);
        }
    }

    /**
     * 绑定当前登录用户信息
     *
     * @param userCurrentInfoDTO 当前用户信息
     */
    public static void setCurrentUser(SipUserCurrentInfoDTO userCurrentInfoDTO) {
        if (userCurrentInfoDTO != null) {
            CURRENT_USER_INFO.set(userCurrentInfoDTO);
        }
    }

    /**
     * 获取用户ip信息
     *
     * @return 用户IP
     */
    public static String getIpAddress() {
        return IP_ADDRESS.get();
    }

    /**
     * 设置用户IP信息
     *
     * @param ipAddress 用户IP
     */
    public static void setIpAddress(String ipAddress) {
        IP_ADDRESS.set(ipAddress);
    }


    /**
     * 资源清理，避免内存增长，一般在请求完成时执行该方法
     */
    public static void clean() {
        IP_ADDRESS.remove();
        AUTHORIZATION.remove();
        IPAAS_SESSION_ID.remove();
        CURRENT_USER_INFO.remove();
        CURRENT_USER_ROLES_INFO.remove();
        IPAAS_TENANT_CODE.remove();
    }

    /**
     * 远程获取Ipaas用户信息
     *
     * @return 用户信息
     */
    private static SipUserCurrentInfoDTO remoteCurrentUser() {
        // 用户身份校验
        String bearerToken = getBearerToken();
        IpaasClientService currentUserContextService = getIpaasClientService();
        return currentUserContextService.getSipUserCurrentInfo(bearerToken);
    }

    /**
     * 远程获取Ipaas组织信息
     *
     * @return 组织信息
     */
    public static SipOrganizationDTO getOrgById(String orgId) {
        // 用户身份校验
        IpaasClientService currentUserContextService = getIpaasClientService();
        return currentUserContextService.getOrgById(orgId);
    }

    /**
     * 根据人员ID获取人员和组织简要信息
     *
     * @return 人员和组织简要信息
     */
    public static SipUserOrgDTO getUserOrgByUserId(String userId, String orgId) {
        Sip3Service sip3Service = applicationContext.getBean(Sip3Service.class);
        SipUserInfoBO sipUserInfoBO = sip3Service.querySipUserInfoBySipUserId(userId);
        SailingAssert.notNull(sipUserInfoBO, "根据用户ID[" + userId + "]查询用户信息失败！");
        SipOrganizationDTO sipOrganizationDTO = getOrgById(orgId);
        SailingAssert.notNull(sipUserInfoBO, "根据用户ID[" + userId + "]查询用户组织信息失败！");
        SipUserOrgDTO sipUserOrgDTO = new SipUserOrgDTO();
        //设置用户
        sipUserOrgDTO.setUserId(sipUserInfoBO.getUserId());
        sipUserOrgDTO.setUserName(sipUserInfoBO.getName());
        sipUserOrgDTO.setMobilePhone(sipUserInfoBO.getMobilePhone());
        sipUserOrgDTO.setIdentityNumber(sipUserInfoBO.getIdentityNumber());
        // 设置组织
        sipUserOrgDTO.setOrgId(sipOrganizationDTO.getOrgId());
        sipUserOrgDTO.setOrgCode(sipOrganizationDTO.getOrgCode());
        sipUserOrgDTO.setOrgName(sipOrganizationDTO.getOrgName());
        return sipUserOrgDTO;
    }

    public static IpaasClientService getIpaasClientService() {
        return applicationContext.getBean(IpaasClientService.class);
    }

    public static void setIpaasClientProperties(IpaasClientProperties ipaasClientProperties) {
        UserContext.ipaasClientProperties = ipaasClientProperties;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        UserContext.applicationContext = applicationContext;
        setIpaasClientProperties(applicationContext.getBean(IpaasClientProperties.class));
    }


    /***add since 2021-09-30***/
    @Override
    public SailingUserCurrentInfo getCurrentUser() {
        return UserContext.currentUser();
    }

    @Override
    public String getClientIpAddress() {
        return UserContext.getIpAddress();
    }

    @Override
    public String getTenantCode() {
        return UserContext.getUserTenantCode();
    }

    /**
     * 得到当前用户租户ID  add by YaoWei 适配明镜
     *
     * @return 用户租户ID
     */
    public static String getUserTenantCode() {
        return IPAAS_TENANT_CODE.get();
    }

    /**
     * 设置当前用户租户ID add by YaoWei 适配明镜
     *
     * @param tenantCode 租户ID
     */
    public static void setUserTenantCode(String tenantCode) {
        IPAAS_TENANT_CODE.set(tenantCode);
    }

}
